/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/

#include "GamutProfiler.h"
#include "GamutLogger.h"
#include <limits>

namespace Gamut
{
	//! Declare Singleton
	template<> Profiler* Singleton<Profiler>::ms_Singleton = 0;

	// -------------------------------------------------------------------------------------------//
	Profiler::Profiler()
	{
		mTimer.reset();
		mProfile.clear();
		LOGF4("Singleton Profiler (%p) created", this);
	}
	
	// -------------------------------------------------------------------------------------------//
	Profiler::~Profiler()
	{
		double total = mTimer.getMilliSeconds() + .0000001;
		
		// create a log entry for each entry
		for (ProfileMap::iterator iter = mProfile.begin(); iter != mProfile.end(); iter++)
		{
			Profile *ptr = iter->second;
			LOGF4("Profile %s: percent %2.2f%%, avg %.4f, cnt %d, max %.4f, min %.4f", iter->first.c_str(),
				  ptr->totalTime / total*100.0, ptr->totalTime / (double)ptr->cnt, ptr->cnt,
				  ptr->maxTime, ptr->minTime);
			delete ptr;
		}
		mProfile.clear();
		
		LOGF4("Singleton Profiler (%p) destroyed", this);
	}
	
	// -------------------------------------------------------------------------------------------//
	void Profiler::startProfile(std::string name)
	{
		ProfileMap::iterator iter = mProfile.find(name);
		
		// does the name already exist?
		if (iter != mProfile.end())
		{
			Profile *ptr = iter->second;
			ptr->_lastTime = mTimer.getMilliSeconds();
		}
		else
		{
			// new entry, create a new profile and add it to the map
			Profile *newProfile = new Profile();
			newProfile->cnt = 0;
			newProfile->minTime = std::numeric_limits<double>::max();
			newProfile->maxTime = 0.0;
			newProfile->totalTime = 0.0;
			newProfile->_lastTime = mTimer.getMilliSeconds();
			
			mProfile[name] = newProfile;			
		}
	}
	
	// -------------------------------------------------------------------------------------------//
	void Profiler::stopProfile(std::string name)
	{
		ProfileMap::iterator iter = mProfile.find(name);
		double timeDiff;
		
		// no record of entry in map, log warning
		if (iter == mProfile.end())
			LOG2("Unable to find " + name + " in the profile map");
		
		Profile *ptr = iter->second;
		ptr->cnt++;
		
		// check for new max/min times
		timeDiff = mTimer.getMilliSeconds() - ptr->_lastTime;
		if (timeDiff > ptr->maxTime)
			ptr->maxTime = timeDiff;
		if (timeDiff < ptr->minTime)
			ptr->minTime = timeDiff;
		
		ptr->totalTime += timeDiff;		
	}
}
